#include "format.h"
#include <QLibrary>
#include <QDebug>

using namespace std;

#define NAME_OF(f) ((void)sizeof(typeid(f)), #f)

Format::Format(QString name, QString lib, map<QString, Format *>subs)
{
    name_ = name;
    QLibrary myLib(lib);

    if (!myLib.load()) {
        qDebug() << "Failed to load library:" << myLib.errorString();
        return;
    }

    auto get_fmt = (decltype(get_format) *)myLib.resolve(NAME_OF(get_format));
    if (get_fmt) format_ = get_fmt();

    sub_formats_ = subs;

    //views
    auto get_field = (decltype(get_top_field) *)myLib.resolve(NAME_OF(get_top_field));
    if (get_field) top_field_ = get_field();
}

QString Format::name()
{
    return name_;
}

bool Format::isAtomField(FEField *field)
{
    if (!field) return true;
    return field->dissect == nullptr;
}

QString Format::getFieldName(FEField *field)
{
    if (!field) return "";

    return field->name;
}

QString Format::getNodeValue(FEFieldNode node) {
    if (!node.field) return "";
    if (!node.field->display) return "";

    char s[128+1];
    auto l = node.field->display(&node, s, 128);
    s[l] = '\0';
    return s;
}

int64_t Format::dessectField(FERange range, void *context, FEField *field, FEList *list)
{
    if (!field || !field->dissect) return -1;
    return field->dissect(range, context, list);
}

FEField *Format::getTopField(){
    return top_field_;
}

int Format::getSubFormats(FERange range, void *context, vector<SubFormat> &sub_formats) {
    if(!format_ || !format_->get) return -1;

    SubFormat sub_format;
    FEList subs;
    initFEList(&subs, sizeof(FESubFormat));
    format_->get(range, context, &subs);
    auto sub = (FESubFormat *)getNextFEUnit(&subs);
    while (sub) {
        auto it = sub_formats_.find(sub->index);
        if (it != sub_formats_.end()) {
            sub_format.range = sub->range;
            sub_format.context = sub->context;
            sub_format.free = sub->free;
            sub_format.format = it->second;
            sub_formats.push_back(sub_format);
        }
        sub = (FESubFormat *)getNextFEUnit(&subs);
    }
    clearFEList(&subs);
    return 0;
}
